use std::process::{Command, Output};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

/// 切换到指定用户执行 Bash 脚本
///
/// # 参数
/// - `target_user`: 目标用户名
/// - `script`: 要执行的 Bash 脚本内容
/// - `timeout`: 可选超时时间(秒)，默认 60 秒
///
/// # 返回
/// - 成功: 返回命令的输出结果
/// - 失败: 返回错误信息
pub fn execute_as_user(
    target_user: &str,
    script: &str,
    timeout: Option<u64>,
) -> Result<Output, String> {
// 2. 检查目标用户是否存在
    if !user_exists(target_user) {
        return Err(format!("目标用户 {} 不存在", target_user));
    }

    // 3. 设置默认超时时间(60秒)
    let timeout_secs = timeout.unwrap_or(60);
    let timeout_duration = Duration::from_secs(timeout_secs);

    // 将 &str 转换为 String 以获得所有权
    let target_user = target_user.to_string();

    // 构建命令，确保加载目标用户的所有环境变量
    let command = format!(
        r#"
        # 切换到目标用户的主目录
        cd ~{}
        # 加载环境变量
        source ~/.bashrc 2>/dev/null || true
        source ~/.profile 2>/dev/null || true
        source /etc/profile 2>/dev/null || true
        # 执行脚本
        {}
        "#,
        target_user,
        script
    );

    let (sender, receiver) = mpsc::channel();

    // 使用线程执行命令
    thread::spawn(move || {
        // 使用sudo切换到目标用户，并加载其环境变量
        let output = Command::new("sudo")
            .arg("-u")
            .arg(&target_user)
            .arg("-i") // 加载目标用户的完整环境变量
            .arg("-c")
            .arg(format!("/bin/bash -c '{}'", escape_bash(command)))
            .output();

        let _ = sender.send(output);
    });

    // 6. 等待结果或超时
    match receiver.recv_timeout(timeout_duration) {
        Ok(Ok(output)) => {
            if output.status.success() {
                Ok(output)
            } else {
                let stderr = String::from_utf8_lossy(&output.stderr);
                Err(format!("脚本执行失败: {}", stderr))
            }
        }
        Ok(Err(e)) => Err(format!("执行失败: {}", e)),
        Err(_) => Err(format!("执行超时 ({}秒)", timeout_secs)),
    }
}

/// 转义bash命令中的特殊字符
fn escape_bash(s: String) -> String {
    s.replace("'", "'\\''")
}

/// 检查用户是否存在
fn user_exists(username: &str) -> bool {
    Command::new("id")
        .arg("-u")
        .arg(username)
        .output()
        .map(|output| output.status.success())
        .unwrap_or(false)
}
